package nl.hr.minor.mobilelife.j1213.jlr.flow;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONObject;

import android.content.Context;
import android.util.Log;

/**
 * Singleton that manages all levels. If called for the first time, it fetches all levels
 * from the JSON file and loads it into the _levels AarrayList. All levels are initialized at once,
 * so the user does not have to wait when he loads a new level. Levels are NOT zero-indexed.
 * <br />
 * <b>Warning</b>: always call this LevelManager from an AsyncTask, for the class can be busy for a while
 * loading all levels
 * @author Leon
 *
 */
public class LevelManager {

	private static LevelManager _theInstance;
	private ArrayList<FlowLevel> _levels;

	private LevelManager(Context context){
		_levels = new ArrayList<FlowLevel>();
		initializeLevels(context);
	}

	/**
	 * Load the JSON file and load all levels from it
	 * @param context
	 */
	private void initializeLevels(Context context) {
		try {
			
			// open the inputstream from the JSON file
			InputStream is = null;
			is = context.getAssets().open("flow_levels.json");
			
			// wrap the inputstream in a bufferedreader
			BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
			
			// load the whole file into a string via a StringBuilder
			StringBuilder sb = new StringBuilder();
			String line = null;
			try {
				while ((line = reader.readLine()) != null) {
					sb.append(line + "\n");
				}
			} catch (IOException e) {
				e.printStackTrace();
				sb = null;
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				reader = null;
				is = null;
				line = null;
			}
			
			// create the JSON object from the JSONstring
			JSONObject root = new JSONObject(sb.toString());
			
			// if the JSON object contains "levels" array as root, continue
			if(root.has("levels")) {
				
				// fetch the JSONArray "levels"
				JSONArray levelArray = root.getJSONArray("levels");
				
				// loop through the levels array and create a level object from every item
				for(int i = 0; i < levelArray.length(); i++) {
					_levels.add(new FlowLevel(i + 1, levelArray.getJSONObject(i)));
				}
			} else {
				Log.e("LevelParser", "json not valid, levels array not found!");
			}
			
		} catch(Exception e){
			
			// we don't like to end up here...
			e.printStackTrace();
		}
	}

	/**
	 * If the instance does not exist, create one and return it.
	 * @param context
	 * @return the instance
	 */
	public static LevelManager getInstance(Context context){
		if(_theInstance == null){
			_theInstance = new LevelManager(context);
		}
		return _theInstance;
	}
	
	/**
	 * Get a level from the Level ArrayList.
	 * @param levelCode
	 * @return The level if levelCode >= 0 && the Level ArrayList has items && levelCode < _levels.size()
	 */
	public FlowLevel getLevel(int levelCode){
		if(levelCode < 0) return null;
		if(_levels.isEmpty()) return null;
		if(_levels.size() < levelCode) return null;
		
		return _levels.get(levelCode - 1);
	}
	
	/**
	 * @return The whole Level ArrayList
	 */
	public ArrayList<FlowLevel> getLevels(){
		return _levels;
	}

	/**
	 * Get the levelCode of the first level
	 * @return The requested levelCode, otherwise 0 if no levels are available
	 */
	public int getLowestLevelCode() {
		return _levels.size() > 0 ? 1 : 0;
	}
	
	/**
	 * Get the levelCode of the last level
	 * @return The requested levelCode, otherwise 0 if no levels are available
	 */
	public int getHighestLevelCode() {
		return _levels.size() > 0 ? _levels.size() : 0;
	}
}
